from queue import Queue
from threading import Thread


class MetaThread(Thread):
    def __init__(self, func, args: tuple, q: Queue):
        self.func = func
        self.args = args
        self.q = q
        self.results = None
        super(MetaThread, self).__init__()

    def run(self) -> None:
        try:
            if self.args:
                self.results = self.func(*self.args)
            else:
                self.results = self.func()
        finally:
            self.q.get()
            self.q.task_done()

    def get(self):
        return self.results


class Pool(object):
    def __init__(self, size=4):
        self.q = Queue(maxsize=size)

    def apply_async(self, func, args: tuple = None) -> MetaThread:
        self.q.put(0)
        t = MetaThread(func, args, self.q)
        t.start()

        return t

    def join(self):
        self.q.join()
